package com.yunyao.framework.audit;

import com.yunyao.common.constant.enums.AuditStatusEnums;
import com.yunyao.common.constant.enums.ProjectSettlementStatusEnum;
import com.yunyao.common.dto.audit.AuditFlowTypeEnums;
import com.yunyao.common.dto.audit.AuditResultEnums;
import com.yunyao.common.dto.audit.CreateAuditFlowDto;
import com.yunyao.common.exception.AuditException;
import com.yunyao.common.web.enums.ResultMsgEnum;
import com.yunyao.dao.model.BamuSpReconciliationSettlement;
import com.yunyao.dao.service.bamu.IBamuSpReconciliationSettlementService;
import com.yunyao.framework.dto.supplier.SupplierSettlementApprovalDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @author xingjishuai
 * @date 2024-08-01
 */
@Slf4j
@Component
public class SupplierSettlementAuditHandle extends AbstractAuditFlowHandle {
    @Autowired
    private IBamuSpReconciliationSettlementService iBamuSpReconciliationSettlementService;

    /**
     * 提交供应商结算审批
     * 本方法负责启动供应商结算的审批流程它首先通过业务ID检索结算信息，
     * 检查数据的合法性，然后创建审批流程实例，并更新结算信息以反映审批流程的启动
     *
     * @param bizId 供应商结算的业务ID
     * @throws AuditException 如果审批流程启动过程中出现错误，将抛出此异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void submit(String bizId) throws AuditException {
        // 通过ID和删除状态获取供应商结算信息
        BamuSpReconciliationSettlement reconciliationSettlement =
                iBamuSpReconciliationSettlementService.getByIdAndDeleted(bizId);
        // 获取合同名称和结算状态
        String contractName = reconciliationSettlement.getContractName();
        Integer status = reconciliationSettlement.getStatus();
        String reconciliationSettlementId = defaultAuditModelInfo.getReconciliationSettlementId();

        try {
            // 检查提交的数据是否合法
            checkSubmitData(reconciliationSettlement);
            // 创建审批流程实例
            CreateAuditFlowDto createAuditFlowDto = creatFlow(reconciliationSettlementId,
                    AuditFlowTypeEnums.MODEL_NAME_SP_RECONCILIATION_SETTLEMENT.getType(), bizId,
                    contractName, String.valueOf(status));

            // 将审批流程实例的信息更新到结算信息中
            reconciliationSettlement.setProcessInstanceId(createAuditFlowDto.getProcessInstanceId());
            reconciliationSettlement.setDeploymentId(createAuditFlowDto.getDeploymentId());
            reconciliationSettlement.setModelSchemeInfoId(createAuditFlowDto.getModelSchemeInfoId());
            reconciliationSettlement.setProcessVersion(createAuditFlowDto.getProcessVersion());

            // 设置结算信息的审批状态为“审批中”
            reconciliationSettlement.setAuditStatus(String.valueOf(AuditStatusEnums.AUDIT.getType()));

            // 更新数据库中的供应商结算信息
            iBamuSpReconciliationSettlementService.updateById(reconciliationSettlement);
        } catch (Exception e) {
            // 记录日志，并抛出审批异常
            log.error("供应商结算submit approval error", e);
            throw new AuditException(e.getMessage());
        }
    }



    /**
     * 审批供应商结算
     *
     * @param approvalDto 审批DTO，包含审批相关信息
     * @throws AuditException 审批过程中发生异常时抛出
     */
    @Transactional(rollbackFor = Exception.class)
    public void approval(SupplierSettlementApprovalDto approvalDto) throws AuditException {
        try {
            // 提取业务ID
            String bizId = approvalDto.getId();
            // 提取审批结果
            Boolean auditResult = approvalDto.getAuditResult();
            // 根据审批结果转换为对应的审批状态字符串
            String auditResultStr = auditResult ? AuditResultEnums.AGREE.getKey() :
                    AuditResultEnums.REJECT.getKey();
            // 通过业务ID查询结算信息
            BamuSpReconciliationSettlement reconciliationSettlement =
                    iBamuSpReconciliationSettlementService.getByIdAndDeleted(bizId);
            // 检查审批数据是否有效
            checkApprovalData(reconciliationSettlement);
            // 执行审批流程，判断是否为流程的最后一步
            boolean isEnd = executeFlow(reconciliationSettlement.getProcessInstanceId(),
                    reconciliationSettlement.getDeploymentId(), auditResultStr,
                    approvalDto.getAuditResultMsg(), approvalDto.getAuditFileList());
            // 如果不是最后一步，则直接返回
            if (!isEnd) {
                return;
            }
            // 根据审批结果设置结算状态
            if (auditResult) {
                reconciliationSettlement.setAuditStatus(String.valueOf(AuditStatusEnums.AUDIT_SUCCESS.getType()));
                reconciliationSettlement.setStatus(ProjectSettlementStatusEnum.CONFIRMED_BY_SUPPLIER.getType());
            } else {
                reconciliationSettlement.setAuditStatus(String.valueOf(AuditStatusEnums.AUDIT_REJECT.getType()));
            }
            // 更新结算信息
            iBamuSpReconciliationSettlementService.updateById(reconciliationSettlement);
        } catch (Exception e) {
            // 记录审批异常日志
            log.error("供应商结算 approval error", e);
            // 抛出审批异常，将异常信息传递给上层调用者
            throw new AuditException(e.getMessage());
        }
    }


    /**
     * 检查审批数据的有效性
     *
     * 此方法对传入的对账结算数据进行检查，确保其满足进行审批流程的条件
     * 主要检查包括数据非空检查，审批状态检查，以及流程实例ID和部署ID的存在性检查
     *
     * @param reconciliationSettlement 待检查的对账结算数据
     * @throws AuditException 如果数据校验不通过，抛出审批异常
     */
    private void checkApprovalData(BamuSpReconciliationSettlement reconciliationSettlement) throws AuditException {
        // 检查对账结算数据是否为空
        if (Objects.isNull(reconciliationSettlement)) {
            throw new AuditException(ResultMsgEnum.NO_DATA);
        }
        // 获取并解析审批状态
        String auditStatus = reconciliationSettlement.getAuditStatus();
        // 确保当前状态为审批中
        if (AuditStatusEnums.AUDIT.getType() != Integer.parseInt(auditStatus)) {
            throw new AuditException(ResultMsgEnum.SUBMIT_AUDIT_STATUS_ERROR);
        }
        // 获取流程实例ID并检查其非空性
        String processInstanceId = reconciliationSettlement.getProcessInstanceId();
        if (StringUtils.isBlank(processInstanceId)) {
            throw new AuditException("processInstanceId is null");
        }
        // 获取部署ID并检查其非空性
        String deploymentId = reconciliationSettlement.getDeploymentId();
        if (StringUtils.isBlank(deploymentId)) {
            throw new AuditException("deploymentId is null");
        }
    }

    /**
     * 检查用户是否具有审核按钮权限
     *
     * 此方法用于确定当前用户是否具有针对特定方案信息和流程实例的审核权限
     * 它通过调用另一个方法来实际执行权限检查逻辑，并且在异常情况下记录错误信息
     *
     * @param schemeInfoId 方案信息ID，用于识别特定的方案
     * @param processInstanceId 流程实例ID，用于识别特定的流程实例
     * @return 如果用户具有审核权限返回true，否则返回false
     */
    public boolean userIsAuditButton(String schemeInfoId, String processInstanceId) {
        try {
            // 调用isCheckAudit方法来判断用户是否具有审核权限
            return isCheckAudit(schemeInfoId, processInstanceId);
        } catch (Exception e) {
            // 记录异常信息，提示项目结算审核按钮权限检查出错
            log.info("项目结算userIsAuditButton error:{}", e.getMessage());
            return false;
        }
    }

    /**
     * 检查提交的审核数据是否有效
     *
     * @param reconciliationSettlement 待审核的对账单结算对象
     * @throws AuditException 如果数据无效或审核状态相互冲突，抛出审核异常
     */
    private void checkSubmitData(BamuSpReconciliationSettlement reconciliationSettlement) throws AuditException {
        // 检查传入的待审核对象是否为空
        if (Objects.isNull(reconciliationSettlement)) {
            // 如果为空，抛出异常，表示没有数据可供审核
            throw new AuditException(ResultMsgEnum.NO_DATA);
        }

        // 获取审核状态字符串
        String auditStatus = reconciliationSettlement.getAuditStatus();
        // 检查审核状态是否处于互斥状态
        if (AuditStatusEnums.AUDIT.getType() == Integer.parseInt(auditStatus)
                && AuditStatusEnums.AUDIT_SUCCESS.getType() == Integer.parseInt(auditStatus)
                && AuditStatusEnums.AUDIT_REJECT.getType() == Integer.parseInt(auditStatus)) {
            // 如果审核状态相互冲突，抛出异常，表示提交的审核状态错误
            throw new AuditException(ResultMsgEnum.SUBMIT_AUDIT_STATUS_ERROR);
        }
    }


}
